
// Copyright 2010 William Malone (www.williammalone.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var canvas;
var context;
var canvasWidth = 727;
var canvasHeight = 531;
var padding = 25;
var lineWidth = 8;

var topCustom = 0;

var colorBlack = new Object();
colorBlack.r = 0;
colorBlack.g = 0;
colorBlack.b = 0;

var color = [colorBlack];
var curColorIndex = 0;
var curColor = colorBlack;

var outlineImage = new Image();
var paintImage = new Image();
var crayonImage = new Image();
var markerImage = new Image();
var eraserImage = new Image();
var khungtranhImage = new Image();
var crayonBackgroundImage = new Image();
var markerBackgroundImage = new Image();
var eraserBackgroundImage = new Image();
var crayonTextureImage = new Image();
var clickX = new Array();
var clickY = new Array();
var clickColor = new Array();
var clickTool = new Array();
var clickSize = new Array();
var clickDrag = new Array();
var clickAirX = new Array();
var clickAirY = new Array();
var clickRadius = new Array();
var clickFillX = new Array();
var clickFillY = new Array();
var history = new Array();
var paint = false;
var move = false;
var curTool = "crayon";
var curSize = "normal";
var mediumStartX = 18;
var mediumStartY = 19;
var mediumImageWidth = 93;
var mediumImageHeight = 46;
var drawingAreaX = 0;
var drawingAreaY = 0;
var drawingAreaWidth = 727;
var drawingAreaHeight = 531;
var toolHotspotStartY = 23;
var toolHotspotHeight = 38;
var sizeHotspotStartY = 157;
var sizeHotspotHeight = 36;
var sizeHotspotWidthObject = new Object();
sizeHotspotWidthObject.huge = 39;
sizeHotspotWidthObject.large = 25;
sizeHotspotWidthObject.normal = 18;
sizeHotspotWidthObject.small = 16;
var totalLoadResources = 9;
var curLoadResNum = 0;
var radius = 2;

var outlineLayerData;
var colorLayerData;
var tempLayerData;
var khungtranhLayerData;
var pixelVisited;
var neighbors = [[1,0], [0,-1], [-1,0], [0,1], [1,1], [1,-1], [-1,-1], [-1,1]];
var pixelStack = new Array();
var newColorR;
var newColorG;
var newColorB;
var newColorA;
var clickedColorR;
var clickedColorG;
var clickedColorB;
var clickedColorA;
var pixelsDrawn;
var moveX;
var moveY;
var scale = 1;
var zoomIn = false;

var paths = new Array();
var shapeX, shapeY, shapeW, shapeH, shapeColor = '#000000';
/**
* Calls the redraw function after all neccessary resources are loaded.
*/
function resourceLoaded()
{
	if(++curLoadResNum >= totalLoadResources){
		redraw();
	}
}

/**
* Creates a canvas element, loads images, adds events, and draws the canvas for the first time.
*/
function prepareCanvas(editImageSrc, outlineImageSrc)
{
	if(editImageSrc==undefined||editImageSrc=='') editImageSrc = '';
	if(outlineImageSrc==undefined||outlineImageSrc=='') outlineImageSrc = '';
	outlineImage = new Image();
    editImage = new Image();
	paintImage = new Image();
	crayonImage = new Image();
	markerImage = new Image();
	eraserImage = new Image();
	khungtranhImage = new Image();
	crayonBackgroundImage = new Image();
	markerBackgroundImage = new Image();
	eraserBackgroundImage = new Image();
	crayonTextureImage = new Image();
	outlineLayerData = '';
	colorLayerData = '';
	tempLayerData = '';
	khungtranhLayerData = '';
	clickX = new Array();
	clickY = new Array();
	clickColor = new Array();
	clickTool = new Array();
	clickSize = new Array();
	clickDrag = new Array();
	clickAirX = new Array();
	clickAirY = new Array();
	clickRadius = new Array();
	clickFillX = new Array();
	clickFillY = new Array();
	// Create the canvas (Neccessary for IE because it doesn't know what a canvas element is)
	var canvasDiv = document.getElementById('canvasDiv');
	canvas = document.createElement('canvas');
	canvas.setAttribute('width', canvasWidth);
	canvas.setAttribute('height', canvasHeight);
	canvas.setAttribute('id', 'canvas');
	canvasDiv.appendChild(canvas);
	if(typeof G_vmlCanvasManager != 'undefined') {
		canvas = G_vmlCanvasManager.initElement(canvas);
	}
	context = canvas.getContext("2d"); // Grab the 2d canvas context
	// Note: The above code is a workaround for IE 8 and lower. Otherwise we could have used:
	//     context = document.getElementById('canvas').getContext("2d");
	
	// Load images
	// -----------
	crayonImage.onload = function() { resourceLoaded(); 
	};
	crayonImage.src = base_url + "images/crayon-outline.png";
	// context.drawImage(crayonImage, 0, 0, 100, 100);
	
	khungtranhImage.onload = function() { resourceLoaded(); 
	};
	khungtranhImage.src = base_url + "img/imgbg.png";
	
	eraserImage.onload = function() { resourceLoaded(); 
	};
	eraserImage.src = base_url + "images/eraser-outline.png";	
	
	crayonBackgroundImage.onload = function() { resourceLoaded(); 
	};
	crayonBackgroundImage.src = base_url + "images/bg.jpg";
	
	markerBackgroundImage.onload = function() { resourceLoaded(); 
	};
	markerBackgroundImage.src = base_url + "images/bg.jpg";
	
	eraserBackgroundImage.onload = function() { resourceLoaded(); 
	};
	eraserBackgroundImage.src = base_url + "images/bg.jpg";
	
	crayonTextureImage.onload = function() { resourceLoaded(); 
	};
	crayonTextureImage.src = base_url + "images/crayon-texture.png";

	outlineImage.onload = function() { 
		setTimeout(function(){
			clearCanvasTransparent();
			context.drawImage(khungtranhImage, 0, 0, drawingAreaWidth, drawingAreaHeight);
			khungtranhLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
		
			clearCanvasTransparent();
			context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
			outlineLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
			if(!editne) {
				clearCanvas();
				colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
				resourceLoaded(); 
			}
		}, 500);
	};
	if(editne){
		editImage.onload = function() { 
			setTimeout(function(){
				context.drawImage(editImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
				colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
				resourceLoaded(); 
			}, 500);
		}
	}
	if(outlineImageSrc!='') outlineImage.src = outlineImageSrc;
	if(editImageSrc!='') editImage.src = editImageSrc;

	// Add mouse events
	// ----------------
	$('#canvas').mousedown(function(e)
	{
		e.originalEvent.preventDefault();
		if(toolChoose<=0) return;

		if(curTool=='flood'){
			history.push(scaleImageData(colorLayerData,1));
		}else{
			history.push(colorLayerData);
		}

		// Mouse down location
		if(zoomIn) {ox = -50;oy = -213;radio=1.5;}
    	else {ox = 0;oy = 0;radio=1;}
		var offsetLeft =  $('#canvasDiv')[0].scrollLeft + ox;
		var offsetTop = $('#canvasDiv')[0].scrollTop + oy;

		var mouseX = e.pageX - this.offsetLeft - $('.container')[0].offsetLeft + offsetLeft;
		var mouseY = e.pageY - this.offsetTop + topCustom  + offsetTop;

		if(curTool=='flood') paintAt(mouseX/radio, mouseY/radio);
		paint = true;
		addClick(mouseX, mouseY, false);
		for(m=0;m<radius*4;m++){
			clickAirX.push(Math.random()*radius-Math.random()*radius);
			clickAirY.push(Math.random()*radius-Math.random()*radius);
		}
		redraw();
	});
	
	$('#canvas').mousemove(function(e){
		if(toolChoose<=0) return;
		if(paint==true){
			if(zoomIn) {ox = -50;oy = -213;radio=1.5;}
	    	else {ox = 0;oy = 0;radio=1;}
			var offsetLeft =  $('#canvasDiv')[0].scrollLeft + ox;
			var offsetTop = $('#canvasDiv')[0].scrollTop + oy;
			addClick(e.pageX - this.offsetLeft - $('.container')[0].offsetLeft + offsetLeft, e.pageY - this.offsetTop + topCustom + offsetTop, true);
			redraw();
		}
	});
	
	$('#canvas').mouseup(function(e){
		if(toolChoose==-1) {
			var mouseX = e.pageX - this.offsetLeft - $('.container')[0].offsetLeft;
			var mouseY = e.pageY - this.offsetTop + topCustom;
			iszoom = true;
			$('.centerel img').click();
			jQuery('.toolbar li').removeClass('active');
			redraw();
			$('#canvasDiv').scrollTop(mouseY/2);
			$('#canvasDiv').scrollLeft(mouseX/2);
		}
		if(toolChoose<=0) return;
	  	resetHistory();
		paint = false;
	  	redraw();
	});
	
	$('#canvas').mouseleave(function(e){
		if(toolChoose<=0) return;
		resetHistory();
		paint = false;
	});
}
function scaleImageData(imageData, scale) {
  var width = imageData.width;
  var height = imageData.height;
  var scaled = context.createImageData(width * scale, height * scale);

  for(var row = 0; row < height; row++) {
    for(var col = 0; col < width; col++) {
      var sourcePixel = [
        imageData.data[(row * width + col) * 4 + 0],
        imageData.data[(row * width + col) * 4 + 1],
        imageData.data[(row * width + col) * 4 + 2],
        imageData.data[(row * width + col) * 4 + 3]
      ];
      for(var y = 0; y < scale; y++) {
        var destRow = row * scale + y;
        for(var x = 0; x < scale; x++) {
          var destCol = col * scale + x;
          for(var i = 0; i < 4; i++) {
            scaled.data[(destRow * scaled.width + destCol) * 4 + i] =
              sourcePixel[i];
          }
        }
      }
    }
  }

  return scaled;
}
/**
* Adds a point to the drawing array.
* @param x
* @param y
* @param dragging
*/
function resetHistory(){
	clickX = new Array();
	clickY = new Array();
	clickColor = new Array();
	clickTool = new Array();
	clickSize = new Array();
	clickDrag = new Array();
	clickAirX = new Array();
	clickAirY = new Array();
	clickRadius = new Array();
	clickFillX = new Array();
	clickFillY = new Array();
}

function addClick(x, y, dragging)
{
	if(zoomIn) radio=1.5;
    else radio=1;
    x = x/radio;
    y = y/radio;
	if(curTool=='eraser'){
		var colorEraser = new Object();
		colorEraser.r = 255;
		colorEraser.g = 255;
		colorEraser.b = 255;
		clickColor.push(colorEraser);
	}
	else clickColor.push(curColor);
	clickX.push(x);
	clickY.push(y);
	clickTool.push(curTool);
	clickSize.push(curSize);
	clickDrag.push(dragging);
	clickRadius.push(radius);
	clickFillX.push(x);
	clickFillY.push(y);
    
    editing = true; 
    outcanvas = false; 
    if(clickX.length > 2){
    	clickColor.shift();
    	clickX.shift();
    	clickY.shift();
    	clickTool.shift();
    	clickSize.shift();
    	clickDrag.shift();
    	clickRadius.shift();
    	clickFillX.shift();
    	clickFillY.shift();
    }
}

/**
* Clears the canvas.
*/
function clearCanvasTransparent()
{
	context.clearRect(0, 0, canvasWidth, canvasHeight);
	// context.fillStyle = '#ffffff'; // Work around for Chrome
	// context.fillRect(0, 0, canvasWidth, canvasHeight); // Fill in the canvas with white
}
function clearCanvas()
{
	// context.clearRect(0, 0, canvasWidth, canvasHeight);
	context.fillStyle = '#ffffff'; // Work around for Chrome
	context.fillRect(0, 0, canvasWidth, canvasHeight); // Fill in the canvas with white
}

/**
* Redraws the canvas.
*/
function redraw()
{
	// Make sure required resources are loaded before redrawing
	if(curLoadResNum < totalLoadResources){ return; }

	clearCanvas();

    if(zoomIn) {
    	radio=1.5;
    	$('#canvasDiv').attr('style','overflow: scroll;height: 480px;width: 690px;z-index:1550;position:relative;');
    }
    else{
    	radio=1;
    	$('#canvasDiv').attr('style','');
    }

    $('#canvas').css('height',canvasHeight*radio+'px').css('width',canvasWidth*radio+'px');

	context.putImageData(colorLayerData, 0, 0);

	var i = 0;
	for(; i < clickX.length; i++)
	{	
		if(clickTool[i]=='marker'||clickTool[i] == "eraser"){	
			context.beginPath();
			if(clickDrag[i] && i){
				context.moveTo(clickX[i-1], clickY[i-1]);
				context.lineTo(clickX[i], clickY[i]);
				context.closePath();
			}else{
			    context.arc(clickX[i], clickY[i], clickRadius[i]/2, 0, 2 * Math.PI, false);
			    context.fillStyle = "rgba(" + clickColor[i].r + "," + clickColor[i].g + "," + clickColor[i].b + ",1)";
			    context.fill();
			    continue;
			}
			
			if(clickTool[i] == "eraser"){
				// context.globalCompositeOperation = "destination-out"; // To erase instead of draw over with white
				// context.strokeStyle = 'white';
				context.strokeStyle = "rgba(" + clickColor[i].r + "," + clickColor[i].g + "," + clickColor[i].b + ",1)";
			}else{
				//context.globalCompositeOperation = "source-over";	// To erase instead of draw over with white
				context.strokeStyle = "rgba(" + clickColor[i].r + "," + clickColor[i].g + "," + clickColor[i].b + ",1)";
			}
			context.lineJoin = "round";
			context.lineWidth = clickRadius[i];
			context.stroke();
		}else if(clickTool[i] == "crayon"){
			context.beginPath();
			for(m=0;m<clickRadius[i]*4;m++){
				if(clickDrag[i] && i){
					context.moveTo(clickX[i-1]+clickAirX[m], clickY[i-1]+clickAirY[m]);
					context.lineTo(clickX[i]+clickAirX[m], clickY[i]+clickAirY[m]);
					context.closePath();
				}else{
					context.beginPath();
					context.rect(clickX[i]+clickAirX[m],clickY[i]+clickAirY[m],1,1);
					context.fillStyle = "rgba(" + clickColor[i].r + "," + clickColor[i].g + "," + clickColor[i].b + ",0.2)";
			      	context.fill();
				}
				context.lineJoin = "round";
				context.strokeStyle = "rgba(" + clickColor[i].r + "," + clickColor[i].g + "," + clickColor[i].b + ",0.1)";
				context.lineWidth = 1;
				context.stroke();
		      }
		}
		
	}

	colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
	mergeLayer();
	mergeLayerKhungTranh();
	if(colorLayerData){
		context.putImageData(colorLayerData, 0, 0);
		colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
	}
	// if(!editne) context.drawImage(outlineImage, 0, 0, canvasWidth, canvasHeight);
	//context.globalCompositeOperation = "source-over";// To erase instead of draw over with white
	context.restore();
	context.globalAlpha = 1; // No IE support
}

function mergeLayer() {
  var width = outlineLayerData.width;
  var height = outlineLayerData.height;

  for(var row = 0; row < height; row++) {
    for(var col = 0; col < width; col++) {
      if(outlineLayerData.data[(row * width + col) * 4 + 3]!=0){
      	 colorLayerData.data[(row * width + col) * 4 + 0] = outlineLayerData.data[(row * width + col) * 4 + 0];
         colorLayerData.data[(row * width + col) * 4 + 1] = outlineLayerData.data[(row * width + col) * 4 + 1];
         colorLayerData.data[(row * width + col) * 4 + 2] = outlineLayerData.data[(row * width + col) * 4 + 2];
      }
    }
  }
}

function mergeLayerShape() {
  var width = tempLayerData.width;
  var height = tempLayerData.height;

  for(var row = 0; row < height; row++) {
    for(var col = 0; col < width; col++) {
      if(tempLayerData.data[(row * width + col) * 4 + 3]!=0){
      	 colorLayerData.data[(row * width + col) * 4 + 0] = tempLayerData.data[(row * width + col) * 4 + 0];
         colorLayerData.data[(row * width + col) * 4 + 1] = tempLayerData.data[(row * width + col) * 4 + 1];
         colorLayerData.data[(row * width + col) * 4 + 2] = tempLayerData.data[(row * width + col) * 4 + 2];
      }
    }
  }
}

function mergeLayerKhungTranh() {
  var width = khungtranhLayerData.width;
  var height = khungtranhLayerData.height;

  for(var row = 0; row < height; row++) {
    for(var col = 0; col < width; col++) {
      if(khungtranhLayerData.data[(row * width + col) * 4 + 3]!=0){
      	 colorLayerData.data[(row * width + col) * 4 + 0] = khungtranhLayerData.data[(row * width + col) * 4 + 0];
         colorLayerData.data[(row * width + col) * 4 + 1] = khungtranhLayerData.data[(row * width + col) * 4 + 1];
         colorLayerData.data[(row * width + col) * 4 + 2] = khungtranhLayerData.data[(row * width + col) * 4 + 2];
      }
    }
  }
}
/**
* Paint based on mouse click location
*/
function paintAt(mouseX, mouseY)
{	
	flood(parseInt(mouseX),parseInt(mouseY),false);
}

/**********************************************************/

function flood(startX, startY, undo)
{	
	if(zoomIn) radio=1.5;
    else radio=1;
	var pixelPos = (startY*canvasWidth + startX)*4;
	
	// console.log("outline: " + outlineLayerData.data[pixelPos] +","+ outlineLayerData.data[pixelPos+1] +","+ outlineLayerData.data[pixelPos+2] +","+ outlineLayerData.data[pixelPos+3]);
	
	var r = colorLayerData.data[pixelPos + 0];
	var g = colorLayerData.data[pixelPos + 1];
	var b = colorLayerData.data[pixelPos + 2];
	var a = colorLayerData.data[pixelPos + 3];
	// console.log("clicked color:   " + r +","+ g +","+ b +","+ a);

	clickedColorR = r;
	clickedColorG = g;
	clickedColorB = b;
	clickedColorA = a;
	
	if(undo==false){
		newColorR = curColor.r;
		newColorG = curColor.g;
		newColorB = curColor.b;
		newColorA = 255;
	}else{
		newColorR = 255;
		newColorG = 255;
		newColorB = 255;
		newColorA = 255;
	}
	
	// console.log("new color:   " + newColorR +","+ newColorG +","+ newColorB+","+ newColorA);
	
	if(clickedColorR == newColorR && clickedColorG == newColorG && clickedColorB == newColorB && clickedColorA == newColorA)
	{
	 	// console.log("Return because trying to fill with the same color");
	 	return;
	 }
	 
	 if(outlineLayerData.data[pixelPos] + outlineLayerData.data[pixelPos+1] + outlineLayerData.data[pixelPos+2] <100 && outlineLayerData.data[pixelPos+ 3] == 255)
	{
	 	// console.log("Return because clicked outline: " + outlineLayerData.data[pixelPos+4]);
	 	return;
	 }

	// console.log("PUSH: " + (startX - drawingAreaX - 2) + "," + (startY - drawingAreaY - 2));
    pixelStack = [[startX, startY]];

	floodFill();
} 

function floodFill()
{
	var newPos, x, y, pixelPos, reachLeft, reachRight;
	var drawingBoundLeft = drawingAreaX;
	var drawingBoundTop = drawingAreaY;
	var drawingBoundRight = drawingAreaX + drawingAreaWidth - 1;
	var drawingBoundBottom = drawingAreaY + drawingAreaHeight - 1;
	
	while(pixelStack.length)
    {
		newPos = pixelStack.pop();
		x = newPos[0];
		y = newPos[1];
		
		// console.log("POP: " + (x - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
		
		pixelPos = (y*canvasWidth + x) * 4;
		// Go up as long as the color matches and are inside the canvas
        while(y-- >= drawingBoundTop && matchClickedColor(pixelPos))
		{
			//console.log("UP: " + (x - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
			pixelPos -= canvasWidth * 4;
		}
		pixelPos += canvasWidth * 4;
        ++y;
        reachLeft = false;
		reachRight = false;
		// Go down as long as the color matches and in inside the canvas
        while(y++ < drawingBoundBottom && matchClickedColor(pixelPos))
        {
			colorPixel(pixelPos);
			//console.log("COLOR: " + (x - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
			
			if(x > drawingBoundLeft)
			{
				if(matchClickedColor(pixelPos - 4)){
					if(!reachLeft){
						pixelStack.push([x - 1, y]);
						//console.log("PUSH: " + ((x-1) - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
						reachLeft = true;
					}
				}else if(reachLeft){
					reachLeft = false;
				}
			}
			if(x < drawingBoundRight)
			{
				if(matchClickedColor(pixelPos + 4)){
					if(!reachRight){
						pixelStack.push([x + 1, y]);
						//console.log("PUSH: " + ((x+1) - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
						reachRight = true;
					}
				}else if(reachRight){
					reachRight = false;
				}
			}
			
			pixelPos += canvasWidth * 4;
        }
    }
	redraw();
}

function matchClickedColor(pixelPos)
{
	var ro = outlineLayerData.data[pixelPos];
	var go = outlineLayerData.data[pixelPos+1];
	var bo = outlineLayerData.data[pixelPos+2];
	var ao = outlineLayerData.data[pixelPos+3];
	var r = colorLayerData.data[pixelPos];
	var g = colorLayerData.data[pixelPos+1];
	var b = colorLayerData.data[pixelPos+2];
	var a = colorLayerData.data[pixelPos+3];
	
	// If current pixel is black then it is an outline
	// if(r!=clickedColorR || g!=clickedColorG || b!=clickedColorB || a!=clickedColorA){ return false; } 
	
	// If current pixel matches the new color
	if(r == newColorR && g == newColorG && b == newColorB && a == newColorA) return false;
	// if(!editne) if(ao > 12) return false;

	// r = colorLayerData.data[pixelPos];	
	// g = colorLayerData.data[pixelPos+1];	
	// b = colorLayerData.data[pixelPos+2];
	// a = colorLayerData.data[pixelPos+3];

	// If the current pixel matches the clicked color
	var distance = calPointColor(clickedColorR,clickedColorG,clickedColorB, r,g,b);

	var distance_o = calPointColor(ro,go,bo, 255,255,255);
	if(distance_o < 12 || ao < 12){
		outlineLayerData.data[pixelPos+3] = 0;
	}
	if(distance < 12 && a == clickedColorA && (distance_o < 12 || ao < 12)) return true;



	return false;
}

function calPointColor(r1,g1,b1, r2,g2,b2){
	return Math.sqrt(Math.pow(r2 - r1,2) + Math.pow(g2 - g1,2) + Math.pow(b2 - b1,2));
}

function colorPixel(pixelPos)
{
	colorLayerData.data[pixelPos] = newColorR;
	colorLayerData.data[pixelPos+1] = newColorG;
	colorLayerData.data[pixelPos+2] = newColorB;
	colorLayerData.data[pixelPos+3] = newColorA;
}

